iT邦幫忙

2026 iThome 鐵人賽

DAY 21
0
Software Development

同一套 Laravel 系統,測試怎麼寫才不會說謊系列 第 21

Day 21:XML 容錯測試——用症狀驗證,不用內部實作細節驗證

  • 分享至 

  • xImage
  •  

前言

「要測試一段字串清洗邏輯,是不是要把清洗前後的每個字元都比對過一次?」

今天要看的是這個系統處理外部系統傳回的髒 XML 資料時,用的一種很精簡的測試手法:不逐欄位比對清洗前後的完整內容,而是只驗證一件事——「清洗過後的字串裡,不該再出現的東西,真的不見了」。這種「用症狀驗證」的方式,反而比鉅細靡遺比對每個字元更穩固。

今日目標

  • 看一段處理外部系統髒資料的容錯邏輯實際在做什麼
  • 理解「用症狀驗證」跟「逐欄位比對」兩種測試手法的差異
  • 認識這段防禦邏輯站在別人踩過的坑上,不是憑空發明
  • 建立判斷力:什麼時候該驗證症狀,什麼時候該驗證完整內容

外部系統偶爾會傳回髒掉的 XML

外部系統回傳的資料裡,偶爾會夾雜一些不合法的 XML 字元——例如某些控制字元被編碼成  這種 HTML entity 格式,如果直接拿去解析 XML,會讓解析器出錯甚至整段資料處理失敗。這個系統有一段字串清洗邏輯,專門處理這種情況:先把這類 HTML entity 編碼的字元轉換回原本的 UTF-8 字元,再用正則加上逐字元檢查的方式,把不合法的控制字元跟殘留的無效 UTF-8 序列過濾掉。

兩種測試手法的對照

逐欄位比對清洗前後的完整內容

test('sanitizes xml string', function () {
    $dirty = '<data>王小明 &#x2; 02-1234-5678 &#x2; test@example.edu</data>';
    $clean = sanitizeXML($dirty);

    expect($clean)->toBe('<data>王小明  02-1234-5678  test@example.edu</data>');
});

這種寫法要準確預測清洗過後每一個字元會變成什麼樣子,一旦清洗邏輯有任何微調(例如改成保留一個空白而不是完全刪除),這支測試就要跟著改斷言內容,維護成本高,而且如果測試資料裡放了看起來像真實個資的內容,還會帶來額外的去識別化風險。

只驗證「不該出現的東西真的不見了」

test('strips invalid xml characters', function () {
    $dirty = '<data>' . str_repeat('sample text ', 3) . '&#x2;</data>';

    $clean = sanitizeXML($dirty);

    expect($clean)->not->toMatch('/&#x(\d+);/');
});

不管清洗邏輯的實作細節怎麼調整,這支測試只問一個問題:「清洗完的字串裡,還找不找得到這種需要被清掉的 pattern」。清洗邏輯內部要用轉碼、正則、還是逐字元檢查來達成,測試完全不在乎,只在乎最終症狀有沒有消失——這讓測試對實作細節的變動更有彈性,同時也不需要在測試資料裡放進任何看起來像真實資料的內容。

這段防禦邏輯不是憑空發明的

查這段清洗邏輯的版本歷史,只能追到一次「升級時把檔案搬過去」的紀錄,找不到最初撰寫這段邏輯的原始 commit。程式碼裡的註解直接附上了一篇公開技術文章的連結,說明這個處理 XML 非法字元的手法是站在別人已經踩過的坑上,不是這個團隊自己憑空發明的解法。誠實承認「這裡抄的是公開資源」,比暗示這是原創解法更貼近真實情況——遇到別人已經解決過的通用問題,直接引用已驗證過的做法,本來就是合理的選擇,不需要為了塑造原創性硬掰一套自己的說法。

今日思考題

回想你手上專案裡有沒有類似「清洗字串、過濾不合法內容」這類防禦性邏輯,測試是逐欄位比對完整輸出,還是只驗證「不該出現的東西真的不見了」?如果實作細節之後要調整,哪一種測試改起來的成本比較低?

今日重點回顧

  • 外部系統偶爾傳回髒 XML,系統用轉碼加逐字元檢查的方式清洗掉不合法字元
  • 測試只驗證「清洗完的字串裡找不找得到不該出現的 pattern」,不逐欄位比對完整內容
  • 用症狀驗證的測試對實作細節的調整更有彈性,也降低了測試資料本身帶來的風險
  • 這段防禦邏輯引用自公開技術資源,誠實承認站在別人的解法上,不需要硬掰原創

明日預告

明天要講一次真實發生過的測試修正:拿掉一支手動塞假資料的 unit test,換成真的執行上傳流程的整合測試,為什麼後者才真正可信。


上一篇
Day 20:Crawler 測試——目前只有 happy path,這代表什麼風險
下一篇
Day 22:拿掉一支「假」的 unit test——為什麼真實整合測試才可信
系列文
同一套 Laravel 系統,測試怎麼寫才不會說謊22
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言